package com.chensi.admin.web.service.impl;

import com.chensi.admin.web.common.Constants;
import com.chensi.admin.web.domain.WebUser;
import com.chensi.admin.web.dto.mapper.WebUserMapper;
import com.chensi.admin.web.exception.BaseException;
import com.chensi.admin.web.service.WebUserService;
import com.google.common.collect.Lists;
import com.chensi.admin.web.common.BaseErrorCode;
import com.chensi.admin.web.dao.WebUserRepository;
import com.chensi.admin.web.dto.WebRoleDTO;
import com.chensi.admin.web.dto.WebUserDTO;
import com.chensi.admin.web.service.WebRoleService;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.Predicate;
import java.util.List;
import java.util.Optional;

/**
 * @date 2019/6/1916:24
 */
@Service
public class WebUserServiceImpl implements WebUserService {

    private final WebUserRepository webUserRepository;

    private final WebUserMapper webUserMapper;

    private final WebRoleService webRoleService;


    private Integer zero = 0;

    private Integer positive = 1;

    @Autowired
    public WebUserServiceImpl(WebUserRepository webUserRepository, WebUserMapper webUserMapper, WebRoleService webRoleService) {
        this.webUserRepository = webUserRepository;
        this.webUserMapper = webUserMapper;
        this.webRoleService = webRoleService;
    }

    @Override
    public WebUser get(String id) throws BaseException {
        Optional<WebUser> optional = webUserRepository.findById(id);
        if (optional.isPresent()) {
            return optional.get();
        } else {
            throw new BaseException(BaseErrorCode.ITEM_NOT_FOUND.getCode(),
                    BaseErrorCode.ITEM_NOT_FOUND.getMessage(), "找不到该记录");
        }
    }

    @Override
    public void delete(String id) throws BaseException {
        if (id.equals(Constants.SUPER_ADMIN)) {
            throw new BaseException(BaseErrorCode.STATUS_NOT_MATCH.getCode(),
                    BaseErrorCode.STATUS_NOT_MATCH.getMessage(), "该记录不能被删除");
        }
        webUserRepository.findById(id);
        WebUser entity = this.get(id);
        entity.setDeleted(Constants.DELETED_YES);
        webUserRepository.save(entity);
    }

    @Override
    public Page<WebUserDTO> page(String username, Integer pageNum, Integer pageSize) {
        pageNum = Optional.ofNullable(pageNum).filter(n -> n >= zero).orElse(Constants.PAGE_NUM);
        pageSize = Optional.ofNullable(pageSize).filter(n -> n > positive).orElse(Constants.PAGE_SIZE);
        return webUserRepository.findAll(
                (root, query, cb) -> {
                    Predicate p1 = cb.equal(root.get("deleted"), Constants.DELETED_NO);
                    List<Predicate> predicates = Lists.newArrayList(p1);
                    if (StringUtils.isNotBlank(username)) {
                        predicates.add(cb.like(root.get("username"), "%" + username.trim() + "%"));
                    }
                    query.where(predicates.toArray(new Predicate[0]));
                    return query.getRestriction();
                }, PageRequest.of(pageNum, pageSize))
                .map(webUserMapper::toDTO);
    }

    @Override
    public WebUser create(WebUser webUser) throws BaseException {
        if(webUser.getWebRole().getId().equals(Constants.ROLE_ID)){
            throw new BaseException(BaseErrorCode.ITEM_IS_USED.getCode(), BaseErrorCode.ITEM_IS_USED.getMessage(), "无法创建超级管理员！");
        }
        checkUser(webUser.getUsername());
        //sha256加密
        String salt = RandomStringUtils.randomAlphanumeric(20);
        webUser.setPassword(new Sha256Hash(webUser.getPassword(), salt).toHex());
        webUser.setSalt(salt);
        //检查角色是否越权
        checkRole(webUser);
        return webUserRepository.save(webUser);
    }

    @Override
    public WebUser update(WebUser webUser) throws BaseException {
        if (webUserRepository.findByUsernameAndIdNot(webUser.getUsername(), webUser.getId()) != null) {
            throw new BaseException(BaseErrorCode.ITEM_IS_USED.getCode(), BaseErrorCode.ITEM_IS_USED.getMessage(), "用户名已被使用！");
        }
        if ((webUser.getId()).equals(Constants.SUPER_ADMIN) && (!(webUser.getUsername()).equals(Constants.SUPER_ADMIN_USERNAME))) {
            throw new BaseException(BaseErrorCode.ITEM_IS_USED.getCode(), BaseErrorCode.ITEM_IS_USED.getMessage(), "超级管理员用户名称无法被修改！");
        }
        WebUser entity = this.get(webUser.getId());
        webUserMapper.update(entity, webUser);
        //检查角色是否越权
        checkRole(webUser);
        return webUserRepository.save(entity);
    }

    @Override
    public WebUserDTO findById(String id) throws BaseException {
        WebUser entity = this.get(id);
        return webUserMapper.toDTO(entity);
    }

    /**
     * 检查角色是否越权
     */
    private void checkRole(WebUser webUser) throws BaseException {
        if (webUser.getWebRole().getId() == null) {
            return;
        }
        //如果不是超级管理员，则需要判断用户的角色是否自己创建
        if (webUser.getCreateBy().equals(Constants.SUPER_ADMIN)) {
            return;
        }

        //查询用户创建的角色列表
        WebRoleDTO webRoleDTO = webRoleService.get(webUser.getWebRole().getId());

        //判断是否越权
        if (!(webRoleDTO.getId()).equals(webUser.getWebRole().getId())) {
            throw new BaseException(BaseErrorCode.ITEM_NOT_FOUND.getCode(),
                    BaseErrorCode.ITEM_NOT_FOUND.getMessage(), "新增用户所选角色，不是本人创建");
        }
    }


    @Override
    public void checkUser(String username) throws BaseException {
        WebUser user = this.findByUsername(username);
        if (user != null) {
            throw new BaseException(BaseErrorCode.ITEM_IS_USED.getCode(), BaseErrorCode.ITEM_IS_USED.getMessage(), "用户名已存在");
        }
    }

    @Override
    public WebUser findByUsername(String username) {
        return webUserRepository.findByUsername(username);
    }

}
